﻿#include "sqldb_config.h"
#include <mutex>
#include <thread>
#include "log_helper.h"
#include "global_config.h"

#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif

using sqldb::DataBase;

std::shared_ptr<DataBase> _msqldb ;
std::mutex _msql_mtx;

const char DBCONFIG_FILE[] = "httpserver.sql";
const int DBCONFIG_CONTENT_LEN = 10 * 1024;

static bool _bpingsql = [](){
    auto config = ilong::Singleton<ilong::GlobalConfig>::instance();
    if(config->mysql.need_connect==1){
        std::thread([config](){

            for (;;) {
                sleep(30000);
                try{
                    if (sqldb_ping())
                    {
                        sqldb_init(config->mysql.type, config->mysql.conn_url, config->mysql.uname, config->mysql.pswd, config->mysql.init_paras);
                        LOG_ERROR(MAIN_LOG, "sql_reconnect {},{},{},{}", config->mysql.type.data(), config->mysql.conn_url.data(), config->mysql.uname.data(), config->mysql.pswd.data());
                    }
                }
                catch (GeneralException& e)
                {
                    LOG_ERROR(MAIN_LOG, "sql_ping error,err_code={},err_msg={}", e.err_code(), e.err_msg().data());
                }
            }

        }).detach();
    }

	return true;
}();


bool sqldb_init(const string& dbtype, const string& conn_url, const string& uname, const string& pswd, const string& init_paras){
    std::lock_guard<mutex> lck(_msql_mtx);
    try {
        _msqldb = sqldb::SqlDb_InitConn(dbtype, conn_url, uname, pswd, init_paras);
    }catch (GeneralException &e){
        LOG_ERROR(MAIN_LOG,"sql connect error! err_code:{} err_str:{}", e.err_code(), e.err_msg());
        return false;
    }
    return true;
}

bool sqldb_load_config()
{
	//get full path
	std::string config_file;
	config_file.append(DBCONFIG_FILE);

	FILE* fp = NULL;
	fp = fopen(config_file.c_str(), "r");
	if (NULL == fp)
	{
		LOG_ERROR(MAIN_LOG, "wmfe load_dbconfig fopen{} failed", config_file.c_str());
		return false;
	}
	char g_dbconfig_content[DBCONFIG_CONTENT_LEN] = { 0 };
	int isize = fread(g_dbconfig_content, sizeof(char), DBCONFIG_CONTENT_LEN - 1, fp);
	if (isize <= 0)
	{
		LOG_ERROR(MAIN_LOG, "load_dbconfig fread{} failed", config_file.c_str());
		fclose(fp);
		fp = NULL;
		return false;
	}
	g_dbconfig_content[isize] = '\0';
	fclose(fp);
	fp = NULL;
	vector<string> vec_tablesql;
	split(g_dbconfig_content, ";", vec_tablesql);
    for (auto &sql:vec_tablesql) {
        if(sql != "\r\n" && sql != ""){
            std::lock_guard<mutex> lck(_msql_mtx);
            _msqldb->exec_no_query(sql);
        }
    }
	return true;
}

bool sqldb_ping()
{
	std::lock_guard<mutex> lck(_msql_mtx);
	if (!_msqldb) 
		return false;
	return _msqldb->run_ctrl_cmd(sqldb::cc_ping);

}

void split(const string& src, const string& separator, vector<string>& dest)
{
	string str = src;
	string substring;
	string::size_type start = 0, index;

	do
	{
		index = str.find_first_of(separator, start);
		if (index != string::npos)
		{
			substring = str.substr(start, index - start);
			dest.push_back(substring);
			start = index + 1;
		}
	} while (index != string::npos);

	//the last token
	substring = str.substr(start);
	dest.push_back(substring);
}

int64_t sqldb_createtable(const string& dbname, const string& filed_list, bool exist)
{
	string str_exist;
	if (exist)
	{
		str_exist = "IF NOT EXISTS";
	}
	string createtable_sql = "CREATE TABLE " + str_exist + " `" + dbname + "` (";
	string uid = "`uid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'uid',";
	string key = ", PRIMARY KEY (`uid`)";
	createtable_sql += uid + filed_list + key + ")DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci";
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(createtable_sql);
	}
	return 0;
}


int64_t sqldb_droptable(const string& dbname)
{
	string droptable_sql = "DROP TABLE " + dbname;
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(droptable_sql);
	}	return 0;
}

int64_t sqldb_insert(const string& dbname, const string& pl, const string& pd)
{
	//insert into +���������е��ֶΣ�����value���ֶ�����Ӧ�ļ�¼����);
	string insertable_sql = " insert into  " + dbname + " ( " + pl + " ) value ( " + pd + " ) ";
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(insertable_sql);
	}
	
	return 0;
}

int64_t sqldb_delete(const string& dbname, const string& whereStmt)
{
	//DELETE FROM ������ WHERE ������ = ֵ
	string delete_sql = " delete from " + dbname + " where " + whereStmt;
	uint64_t affected_rows = 0;
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(delete_sql);
		_msqldb->run_ctrl_cmd(sqldb::cc_affected_rows, &affected_rows);
	}
	return affected_rows;
}

int64_t sqldb_update(const string& dbname, const string& set_list, const string& wherestmt)
{	
	//UPDATE ������ SET ������ = ��ֵ WHERE ������ = ĳֵ
	string update_sql = " UPDATE " + dbname + " SET " + set_list + " WHERE " + wherestmt;
	uint64_t affected_rows = 0;
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(update_sql);
		_msqldb->run_ctrl_cmd(sqldb::cc_affected_rows, &affected_rows);
	}
	return affected_rows;
}

shared_ptr<ResultSet> sqldb_select(const string& dbname, const string& wantparam, const string& wherestmt)
{
	//SELECT ������ FROM ������ WHERE �� ����� ֵ
	string selete_sql = "SELECT " + wantparam + " FROM " + dbname + " WHERE " + wherestmt;
	shared_ptr<ResultSet> rs;
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		rs = _msqldb->exec_query(selete_sql);
	}

	return rs;
}


int64_t sqldb_select_insertid(const string& dbname, const string& pl, const string& pd)
{
	//insert into +���������е��ֶΣ�����value���ֶ�����Ӧ�ļ�¼����);
	string insertable_sql = " insert into  " + dbname + " ( " + pl + " ) value ( " + pd + " );";
	string selete_sql = "SELECT LAST_INSERT_ID();";
	shared_ptr<ResultSet> rs;
	{
		std::lock_guard<mutex> lck(_msql_mtx);
		_msqldb->exec_no_query(insertable_sql);
		rs = _msqldb->exec_query(selete_sql);
	}
	if (rs->next()) {
		return rs->get_int64(0);
	}
	return -1;
}
